﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;

using Xc.DataAccess.Core;
using Xc.DataAccess.Core.Services;
using Xc.DataAccess.DataBase.DeviceInfos;
using Xc.DataAccess.Protocoals.WaterMeters.Models;
using Xc.DataAccess.Protocoals.WaterMeters.Services;
using Xc.DataAccess.WaterMeters.ClientSides.Services;
using Xc.WaterMeters.ServerHosts.Models;

namespace Xc.WaterMeters.ServerHosts.Services
{
    /// <summary>
    /// 通知其他设备服务
    /// </summary>
    public class NotifyOtherService : MeterHandleService
    {
        private readonly IOptions<AppSettings> options;
        private readonly IHttpClientFactory httpContextFactory;
        private readonly ILogger<IMeterHandleService> logger;
        private readonly IDbCommandInfoService dbCommandInfoService;
        private readonly IWaterDeviceSendService waterDeviceSendService;
        private readonly IConverterService converterService;
        /// <summary>
        /// 通知其他设备服务
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="options"></param>
        /// <param name="httpContextFactory"></param>
        public NotifyOtherService(ILogger<IMeterHandleService> logger, IOptions<AppSettings> options, IHttpClientFactory httpContextFactory, IDbCommandInfoService dbCommandInfoService, IWaterDeviceSendService waterDeviceSendService, IConverterService converterService) : base(logger)
        {
            this.options = options;
            this.httpContextFactory = httpContextFactory;
            this.logger = logger;
            this.dbCommandInfoService = dbCommandInfoService;
            this.waterDeviceSendService = waterDeviceSendService;
            this.converterService = converterService;
        }
        /// <summary>
        /// 将数据通知给其他设备
        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        /// <param name="frameCommand"></param>
        /// <param name="dataSegment"></param>
        /// <param name="devcieId"></param>
        /// <param name="meterType"></param>
        /// <param name="companyId"></param>
        /// <returns></returns>
        protected override async ValueTask NotifyData(IDevcieInfoAppSession devcieInfoAppSession, Type type, object data, FrameCommand frameCommand, DataSegment dataSegment, string devcieId, MeterType meterType, byte companyId)
        {
            if (devcieId == null)
            {
                logger.LogError("无有效的设备编号");
                return;
            }
            await base.NotifyData(devcieInfoAppSession,type, data, frameCommand, dataSegment, devcieId, meterType, companyId);

            var client = httpContextFactory.CreateClient();
            try
            {
                if (options.Value.NotifyPath == null)
                {
                    throw new InvalidOperationException();
                }
                if (options.Value.Notifys.ContainsKey(type.Name))
                {
                    var url = options.Value.Notifys[type.Name];
                    var tasks = url.Select(p => Task.Run(async () =>
                    {
                        try
                        {
                            UriBuilder uriBuilder = new UriBuilder(p);
                            uriBuilder.Query = $"{nameof(frameCommand)}={frameCommand}&{nameof(dataSegment)}={dataSegment}&{nameof(devcieId)}={devcieId}&{nameof(companyId)}={companyId}";
                            var respond = await client.PostAsJsonAsync(uriBuilder.ToString(), data);
                            if (respond.IsSuccessStatusCode)
                            {
                                logger.LogInformation($"device server to plantform:{type.Name}  success");
                            }
                            else
                            {
                                var error = await respond.Content.ReadAsStringAsync();
                                logger.LogInformation($"device server to plantform:{type.Name}  failed! reson:{error}");
                            }
                        }
                        catch (Exception err)
                        {
                            logger.LogError(err.Message, err);
                        }

                    }));
                    await Task.WhenAny(tasks);
                }
                else
                {
                    logger.LogWarning($"订阅类型：{type.Name}无有效的服务器可推送");
                }
            }
            catch (System.Exception err)
            {
                logger.LogError(err.Message, err);
            }
            var commandType= devcieId+(uint)(((byte)frameCommand) * 0x10000 + (ushort)dataSegment);
            var res = dbCommandInfoService.Peek(devcieInfoAppSession.DeviceId);
            if (res.IsSuccess && res.Infos == DataAccess.DataBase.DeviceInfos.Models.SendState.HasData)
            {
                if (res?.Result?.CommandType== commandType)
                {
                    if (frameCommand.ToString().EndsWith("OK"))
                    {
                        res.Result.RespondInfo = new DataAccess.DataBase.DeviceInfos.Models.RespondInfo { RespondDateTime = DateTime.Now };
                        res.Result.Status = DataAccess.DataBase.DeviceInfos.Models.CommandStatus.成功;
                        dbCommandInfoService.Update(res.Result);
                    }
                    else if (frameCommand.ToString().EndsWith("NG"))
                    {
                        res.Result.Status = DataAccess.DataBase.DeviceInfos.Models.CommandStatus.失败;
                        dbCommandInfoService.Update(res.Result);
                    }
                }
            }
        }
        /// <summary>
        /// 请求之前触发
        /// </summary>
        /// <typeparam name="TData"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public override Result BeforeRequest<TData>(TData data)
        {
            if (data.DevcieId==null||data.DevcieId.Length%2!=0)
            {
                return Result.Reject("设备编号长度必须为偶数，且只能包含0-9,A-F");
            }
          return   dbCommandInfoService.Push(new DataAccess.DataBase.DeviceInfos.Models.CommandInfoAdd { CommandName = data.GetType().Name, CommandId = Guid.NewGuid(), RequestInfo = new DataAccess.DataBase.DeviceInfos.Models.RequestInfo { CreateDateTime = DateTime.Now, HexContent = data.FullFrame.ToArray(), StringContent = converterService.ToJsonString(data) }, CommandType = data.CommandType,DeviceInfoId=data.DevcieId }); ;
        }
        /// <summary>
        /// 请求完毕后执行
        /// </summary>
        /// <typeparam name="TData"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        public override async ValueTask<ResultData<TData, byte[]>> AfterRequest<TData>(TData data)
        {
            var d=await base.AfterRequest(data);
            if (d.IsSuccess)
            {
                var res = dbCommandInfoService.Peek(data.DevcieId);
                if (res.IsSuccess)
                {
                    res.Result.Status = DataAccess.DataBase.DeviceInfos.Models.CommandStatus.已发送;
                    dbCommandInfoService.Update(res.Result);
                }
            }
            return d;
        }
        /// <summary>
        /// 设备连接后触发
        /// </summary>
        /// <param name="devcieInfoAppSession"></param>
        protected override async void OnDeviceConnect(IDevcieInfoAppSession devcieInfoAppSession)
        {
            var res=  dbCommandInfoService.Peek(devcieInfoAppSession.DeviceId);
            if (res.IsSuccess&&res.Infos==DataAccess.DataBase.DeviceInfos.Models.SendState.HasData)
            {
                var obj = converterService.FromJsonString<object>(res?.Result?.RequestInfo?.StringContent);
                await  waterDeviceSendService.RequestCore(obj,res.Result.CommandName);
                res.Result.Status = DataAccess.DataBase.DeviceInfos.Models.CommandStatus.已发送;
                dbCommandInfoService.Update(res.Result);
            }
            base.OnDeviceConnect(devcieInfoAppSession);
        }
    }

}
